﻿/*
 * Created by SharpDevelop.
 * User: sanmadmin
 * Date: 6/17/2011
 * Time: 2:48 AM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace RTMP
{
	/// <summary>
	/// Description of BaseSocket.
	/// </summary>
	public class BaseSocket
	{
        private static ManualResetEvent TIMOConnect=new ManualResetEvent(false);
        private static ManualResetEvent TIMOSend=new ManualResetEvent(false);
        private static ManualResetEvent TIMOReceive=new ManualResetEvent(false);
		public bool bConnected=false;
		public Socket m_socket=null;
		public int ReceiveTimeoutAsync=10000;
		public int SendTimeoutAsync=10000;
        public static string strLastError=string.Empty;
        public static int nLastErrorCode=0;
		public string m_IP;
		public int m_PORT;
        public delegate void ConnectReadyDelegate(object sender,ConnectReadyArgs e);
        public delegate void SendReadyDelegate(object sender,SendReadyArgs e);
        public delegate void ReceiveReadyDelegate(object sender,ReceiveReadyArgs e);
        public delegate void BaseSocketErrorDelegate(object sender,SocketException e);
        public delegate void BaseSocketObjectErrorDelegate(object sender, BaseSocketObjectErrorArgs e);
        public event ConnectReadyDelegate ConnectReady;
        public event SendReadyDelegate SendReady;
        public event ReceiveReadyDelegate ReceiveReady;
        public event BaseSocketErrorDelegate BaseSocketError;
        public event BaseSocketObjectErrorDelegate BaseSocketObjectError;
        
        public delegate void ReceiveReadyHandler(byte firstbyte);
        
		public BaseSocket(string IP,int PORT)
		{
			m_PORT=PORT;
			m_IP=IP;
			m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
		}
		public BaseSocket()
		{
			m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
		}
		public bool Connect(int TIMO=10)
		{
			return ConnectSync(TIMO);
		}
		public void Connect()
		{
			ConnectAsync();
		}
		private bool ConnectSync(int TIMO)
		{
        	TIMOConnect.Reset();
        	TIMO=TIMO*1000;
        	m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        	m_socket.BeginConnect(m_IP,m_PORT,new AsyncCallback(ConnectCallbackSync),m_socket);
        	strLastError="";
        	if(TIMOConnect.WaitOne(TIMO,false))
			{
        		if(bConnected)
        		{
        			return true;
        		}
        		else
        			return false;
			}
        	else
        	{
        		return false;
        	}
		}
        private void ConnectCallbackSync(IAsyncResult ias)
        {
        	/*try
        	{*/
        		Socket sclient=(Socket) ias.AsyncState;
        		if(sclient!=null)
        		{
	        		sclient.EndConnect(ias);
	        		sclient.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.DontLinger,false);
        			bConnected=true;
        		}
        		else
        			bConnected=false;
        	/*}
        	catch(SocketException se)
        	{
        		bConnected=false;
        		strLastError=se.Message;
        		nLastErrorCode=se.ErrorCode;        		
        	}
        	catch(Exception ex)
        	{
        		bConnected=false;
        		strLastError=ex.Message;
        	}
        	finally
        	{*/
        		TIMOConnect.Set();
        	//}
        }
        private void ConnectAsync()
        {
         	strLastError=string.Empty;
	       	TIMOConnect.Reset();
        	m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        	m_socket.BeginConnect(m_IP,m_PORT,new AsyncCallback(ConnectCallbackAsync),m_socket);
        }
        private void ConnectCallbackAsync(IAsyncResult ias)
        {
        	/*try
        	{*/
        		Socket sclient=(Socket) ias.AsyncState;
        		if(sclient!=null)
        		{
        			sclient.EndConnect(ias);
        			bConnected=true;
        		}
        		OnConnectReady();
        	/*}
        	catch(SocketException se)
        	{
        		bConnected=false;
        		OnBaseSocketError(se);
        	}
        	catch(Exception ex)
        	{
        		bConnected=false;
        		OnBaseSocketObjectError(ex.Message);
        	}*/
        }
        public bool Send(byte[] message, int TIMO)
        {
        	if(!bConnected)
        		return false;
        	return SendSync(message,TIMO);
        }
        public bool Send(byte[] message,int offset,int length, int TIMO)
        {
        	if(!bConnected)
        		return false;
        	return SendSync(message,offset,length,TIMO);
        }
        public void Send(byte[] message)
        {
        	if(!bConnected)
        		return;
        	SendAsync(message);
        }
        public void Send(byte[] message,int offset,int length)
        {
        	if(!bConnected)
        		return;
        	SendAsync(message,offset,length);
        }
        private bool SendSync(byte[] buffer,int TIMO)
        {
         	strLastError="";
	       	TIMOSend.Reset();
	       	ServerPacket sp=new ServerPacket();
	       	sp.server=m_socket;
	       	m_socket.BeginSend(buffer,0,buffer.Length,SocketFlags.None,new AsyncCallback(SendCallbackSync),sp);
        	if(TIMOSend.WaitOne(TIMO,false))
        	{
        		if(sp.successed)
        			return true;
        		return false;
        	}
        	else
        		return false;
		}
        private bool SendSync(byte[] buffer,int offset,int length,int TIMO)
        {
         	strLastError="";
	       	TIMOSend.Reset();
	       	ServerPacket sp=new ServerPacket();
	       	sp.server=m_socket;
	       	m_socket.BeginSend(buffer,offset,length,SocketFlags.None,new AsyncCallback(SendCallbackSync),sp);
        	if(TIMOSend.WaitOne(TIMO,false))
        	{
        		if(sp.successed)
        			return true;
        		return false;
        	}
        	else
        		return false;
		}
        private static void SendCallbackSync(IAsyncResult ias)
        {
			ServerPacket sp=null;
        	/*try
			{*/
	        	sp=(ServerPacket)ias.AsyncState;
				int send=sp.server.EndSend(ias);
				sp.successed=true;
			/*}
			catch(SocketException se)
			{
				strLastError=se.Message;
				nLastErrorCode=se.ErrorCode;
				sp.successed=false;
			}
			catch(Exception e)
			{
				strLastError=e.Message;
				sp.successed=false;
			}*/
    		TIMOSend.Set();
        }
        private void SendAsync(byte[] buffer)
        {
          	strLastError="";
	       	TIMOSend.Reset();
	       	m_socket.BeginSend(buffer,0,buffer.Length,SocketFlags.None,new AsyncCallback(SendCallbackAsync),m_socket);
		}
        private void SendAsync(byte[] buffer,int offset,int length)
        {
          	strLastError="";
	       	TIMOSend.Reset();
	       	m_socket.BeginSend(buffer,offset,length,SocketFlags.None,new AsyncCallback(SendCallbackAsync),m_socket);
		}
        private void SendCallbackAsync(IAsyncResult ias)
        {
			/*try
			{*/
				Socket client=(Socket)ias.AsyncState;
				int send=client.EndSend(ias);
				OnSendReady();
			/*}
			catch(SocketException se)
			{
				OnBaseSocketError(se);
			}
			catch(Exception ex)
			{
				OnBaseSocketObjectError(ex.Message);
			}*/
        }
        public int Receive(ref byte[] buffer,int offset,int length, int TIMO)
        {
        	if(!bConnected)
        		return -1;
        	return ReceiveSync(ref buffer,offset,length,TIMO);
        }
        public int Receive(ref byte[] buffer,int TIMO)
        {
        	if(!bConnected)
        		return -1;
        	return ReceiveSync(ref buffer,0,buffer.Length,TIMO);
        }
        public void Receive(ref byte[] buffer,int offset,int length)
        {
        	if(!bConnected)
        		return;
        	ReceiveAsync(ref buffer,offset,length);
        }        	
        public void Receive(int length)
        {
        	if(!bConnected)
        		return;
        	ReceiveAsync(length);
        }        	
        public void Receive(int length,ReceiveReadyHandler handler)
        {
        	if(!bConnected)
        		return;
        	ReceiveAsync(length,handler);
        }        	
        public void Receive(ref byte[] buffer)
        {
        	if(!bConnected)
        		return;
        	ReceiveAsync(ref buffer);
        }        	
        private int ReceiveSync(ref byte[] buffer,int offset,int length, int TIMO)
        {
        	strLastError="";
	       	TIMOReceive.Reset();
        	ServerPacket sp=new ServerPacket();
        	//sp.buffer=new byte[length];
        	sp.buffer=buffer;
        	sp.server=m_socket;
	       	m_socket.BeginReceive(sp.buffer,offset,length,SocketFlags.None,new AsyncCallback(ReceiveCallbackSync),sp);
        	if(TIMOReceive.WaitOne(TIMO,false))
        	{
        		if(sp.successed)
        		{
        			buffer=sp.buffer;
        			return sp.Received;
        		}
        	}        	
        	return 0;
		}
        private static void ReceiveCallbackSync(IAsyncResult ias)
        {
			ServerPacket sp=null;
			/*try
			{*/
				sp=(ServerPacket)ias.AsyncState;
				sp.Received=sp.server.EndReceive(ias);
				sp.successed=true;
			/*}
			catch(SocketException se)
			{
				strLastError=se.Message;
				nLastErrorCode=se.ErrorCode;
				sp.successed=false;
			}
			catch(Exception ex)
			{
				strLastError=ex.Message;
				sp.successed=false;
			}
			finally
			{*/
	    		TIMOReceive.Set();
			//}
        }
        private void ReceiveAsync(int length)
        {
         	if(!bConnected)
        		return;
	       	strLastError="";
       		ServerPacket sp=new ServerPacket();
       		sp.server=m_socket;
       		sp.buffer=new byte[length];
	       	TIMOReceive.Reset();
	       	m_socket.BeginReceive(sp.buffer,0,length,SocketFlags.None,new AsyncCallback(ReceiveCallbackAsync),sp);
		}
        private void ReceiveAsync(int length,ReceiveReadyHandler handler)
        {
        	if(!bConnected)
        		return;
        	strLastError="";
       		ServerPacket sp=new ServerPacket();
       		sp.server=m_socket;
       		sp.buffer=new byte[length];
       		sp.handler=handler;
	       	TIMOReceive.Reset();
	       	m_socket.BeginReceive(sp.buffer,0,length,SocketFlags.None,new AsyncCallback(ReceiveCallbackAsync),sp);
		}
        private void ReceiveAsync(ref byte[] buffer,int offset,int length)
        {
        	if(!bConnected)
        		return;
          	strLastError="";
       		ServerPacket sp=new ServerPacket();
       		sp.server=m_socket;
       		//sp.buffer=new byte[length];
       		sp.buffer=buffer;
	       	m_socket.BeginReceive(sp.buffer,offset,length,SocketFlags.None,new AsyncCallback(ReceiveCallbackAsync),sp);       		
		}
        private void ReceiveAsync(ref byte[] buffer)
        {
        	if(!bConnected)
        		return;
          	strLastError="";
       		ServerPacket sp=new ServerPacket();
       		//sp.buffer=new byte[buffer.Length];
       		sp.buffer=buffer;
       		sp.server=m_socket;
	       	TIMOReceive.Reset();
	       	m_socket.BeginReceive(sp.buffer,0,buffer.Length,SocketFlags.None,new AsyncCallback(ReceiveCallbackAsync),sp);
		}
        private void ReceiveCallbackAsync(IAsyncResult ias)
        {			
			/*try
			{*/
				ServerPacket sp=(ServerPacket)ias.AsyncState;
				sp.Received=sp.server.EndReceive(ias);
	       		if(sp.handler!=null)
	       			sp.handler(sp.buffer[0]);
	       		else
					OnReceiveReady(true,sp.buffer,sp.Received);
			/*}
			catch(SocketException se)
			{
				OnBaseSocketError(se);
			}
			catch(Exception e)
			{
				OnBaseSocketObjectError(e.Message);
			}*/
        }   
        public void OnConnectReady()
        {
        	if(ConnectReady!=null)
        	{
        		ConnectReadyArgs cra=new ConnectReadyArgs();
        		ConnectReady(this,cra);
        	}
        }
        public void OnSendReady()
        {
        	if(SendReady!=null)
        	{
        		SendReadyArgs ira=new SendReadyArgs();
        		SendReady(this,ira);
        	}
        }
        public void OnReceiveReady(bool bSuccess,byte[] buffer,int received)
        {
        	if(ReceiveReady!=null)
        	{
        		ReceiveReadyArgs ira=new ReceiveReadyArgs(bSuccess,buffer,received);
	       		ReceiveReady(this,ira);
        	}
        }
		private void OnBaseSocketError(SocketException e)
		{
			if(BaseSocketError!=null)
			{
				BaseSocketError(this,e);
			}
		}
		public void OnBaseSocketObjectError(string message)
		{
			if(BaseSocketObjectError!=null)
			{
				BaseSocketObjectErrorArgs bsoea=new BaseSocketObjectErrorArgs(message);
				BaseSocketObjectError(this,bsoea);
			}
		}
		private class ServerPacket
		{
			public byte[] buffer;
			public Socket server;
			public int Received=0;
			public bool successed=false;
			public ReceiveReadyHandler handler=null;
			public ServerPacket()
			{
			}
		}
		public void close()
		{
            if (m_socket != null)
            {
                try
                {
                    m_socket.Shutdown(SocketShutdown.Both);
                    m_socket.Close();
                    bConnected=false;
                }
                catch { }
            }
		}
	}
	public class ConnectReadyArgs : System.EventArgs
	{
		public ConnectReadyArgs() {}
	}
	public class SendReadyArgs : System.EventArgs
	{
		public SendReadyArgs() {}
	}
	public class ReceiveReadyArgs : System.EventArgs
	{
		public bool bSuccess=false;
		public int Received=0;
		public byte[] buffer;		
		public ReceiveReadyArgs(bool success,byte[] buffer,int Received)
		{
			this.buffer=buffer;
			bSuccess=success;
			this.Received=Received;
		}
	}
	public class BaseSocketObjectErrorArgs : System.EventArgs
	{
		public string message=string.Empty;
		public BaseSocketObjectErrorArgs(string message)
		{
			this.message=message;
		}
	}
}
